﻿using System;
using System.Collections.Generic;
using System.Linq;
using Pay.Core;
using Pay.Data;
using Pay.DTO;
using Pay.IService;
using Pay.Service.Cache;
using Pay.TO;

namespace Pay.Service.Service {
    public class UpgradeService : MerchantBillService, IUpgradeService, IDisposable {
        private IUnitOfWork _iUnitOfWork;
        private IGradeService _iGradeService;

        public UpgradeService(IUnitOfWork iUnitOfWork, ISettingService iSettingService, IBillService iBillService,
                           IMerchantService iMerchantService, IPaymentService iPaymentService, IGradeService iGradeService)
            : base(iUnitOfWork, iSettingService, iBillService, iMerchantService, iPaymentService) {
            _iUnitOfWork = iUnitOfWork;
            _iGradeService = iGradeService;
        }

        private const string _key = "pay_charge";

        /// <summary>
        /// 读取订单缓存
        /// </summary>
        /// <param name="bind_no"></param>
        private charge_dto GetCheckout(string bind_no) {
            string key = _key + "-" + bind_no;
            return _iUnitOfWork.GetCache(key) as charge_dto;
        }

        private void SetCheckout(charge_dto charge) {
            string key = _key + "-" + charge.bind_no;
            _iUnitOfWork.SetCache(key, charge);
        }

        public int PaySuceess(string bind_no, string transaction_no, DateTime? pay_time) {
            var order = GetCheckout(bind_no);
            if (order.status != ChargeStatus.WaitPay)
                throw new ServerErrorException("付款" + order.order_no + "非待支付状态时", 1002);
            order.status = ChargeStatus.Finish;
            order.pay_info.pay_time = pay_time ?? DateTime.Now;
            order.pay_info.transaction_no = transaction_no;
            UpgradeAccount(order);
            int result = _iUnitOfWork.Commit();
            if (result > 0) {
                //创建通知消息对象
                _notifyHelper.Save(new Nosql.pay_notify { order_no = order.order_no, pay_channel = order.pay_info.pay_channel, type = 3, status = (int)order.status, create_time = DateTime.Now });
            }
            return result;
        }

        public int PayFailOrUnConfirm(string pay_no, string transaction_no, ChargeStatus status, string fail = "") {
            var order = GetCheckout(pay_no);
            if (order.status != ChargeStatus.WaitPay)
                throw new ServerErrorException("付款" + pay_no + "非待支付状态时", 1002);
            order.status = status;
            order.pay_info.transaction_no = transaction_no;
            order.fail = fail;
            int result = _iUnitOfWork.Commit();
            if (result > 0) {
                //创建通知消息对象
                _notifyHelper.Save(new Nosql.pay_notify { order_no = order.order_no, pay_channel = order.pay_info.pay_channel, type = 3, status = (int)order.status, create_time = DateTime.Now });
            }
            return result;
        }

        public void AddByQuickPay(quick_pay_model model) {
            var dto = model.ToDtoObject<charge_dto>();
            AddByPay(dto, model.merchant_no, model.bind_no, model.tran_amount, model.pay_channel, model.pay_code, model.settle_type);
            SetCheckout(dto);
        }

        private void AddByPay(charge_dto dto, string merchant_no, string bind_no, string tran_amount, PayChannel pay_channel, string pay_code, string settle_type) {
            var merchant = _iMerchantService.Get(merchant_no);
            dto.merchant_id = merchant.id;
            merchant_dto binder = null;
            if (!string.IsNullOrEmpty(bind_no) && bind_no != merchant_no) {
                binder = _iMerchantService.Get(bind_no);
                dto.bind_id = binder.id;
            } else {
                binder = merchant;
                dto.bind_id = dto.merchant_id;
            }
            var payment = binder.payments.FirstOrDefault(c => c.payment.channel == pay_channel && c.payment.code == pay_code);
            if (payment == null)
                payment = binder.grade.payments.FirstOrDefault(c => c.payment.channel == pay_channel && c.payment.code == pay_code);
            var settle = payment.settles.First(c => c.settle_type == settle_type);
            decimal amount = decimal.Parse(tran_amount) / 100;
            if (settle.single_quota > amount || settle.card_quota < amount)
                throw new ServerErrorException("订单金额超出限额", 1001);
            if (dto.fee == 0 || (dto.fee > 0 && dto.fee < settle.fee))//自定义费率
                dto.fee = settle.fee;
            dto.pay_info.pay_name = payment.payment.name;
            dto.status = ChargeStatus.WaitPay;
            dto.pay_amount = dto.order_amount - dto.subsidy_amount;
            dto.fee_amount = dto.pay_amount * dto.fee;
            dto.amount = dto.pay_amount - dto.fee_amount;
            //非常重要，计算是否超出成本
            var profit = dto.profit.Sum(c => (decimal?)c.amount);
            if (amount < profit.Value)
                throw new ServerErrorException("超出成本不可以交易", 1002);
        }
    }
}
